/*
 * $Id: $
 */
package org.rcgwt.client.ui.grid.controller;

import org.rcgwt.client.ui.grid.internal.model.IElementModel;
import org.rcgwt.client.ui.grid.internal.model.IGridModel;
import org.rcgwt.client.ui.grid.internal.model.IStateMasks;
import org.rcgwt.client.ui.grid.internal.model.ITitleCellModel;
import org.rcgwt.client.ui.grid.internal.model.ITitleRowModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModel;
import org.rcgwt.client.ui.grid.model.IGridWidget;
import org.rcgwt.client.ui.grid.provider.IFocusProvider;
import org.rcgwt.client.ui.grid.provider.IOrderProvider;
import org.rcgwt.client.ui.grid.provider.IOverProvider;
import org.rcgwt.client.ui.grid.renderer.IGridRenderContext;
import org.rcgwt.client.ui.grid.renderer.ITitleCellRenderer;
import org.rcgwt.client.ui.grid.renderer.ITitleRowRenderer;
import org.rcgwt.client.ui.grid.renderer.IViewRenderContext;

import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;

/**
 * 
 * @author Olivier Oeuillot (latest modification by $Author: $)
 * @version $Revision: $ $Date: $
 */
public class TitleCellEventController implements IElementModelEventController {

	private int lastActivedTitleCellModelIndex = -1;

	private ITitleCellModel currentPushedTitleCell;

	@Override
	public boolean processFocus(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		IFocusProvider focusProvider = gridWidget.getFocusProvider();
		if (focusProvider == null) {
			return false;
		}

		ITitleCellModel titleCellModel;

		IViewModel viewModel = DefaultGridController.getViewModel(gridWidget,
				event);

		switch (elementModel.getType()) {
		case TITLE_CELL:
			titleCellModel = (ITitleCellModel) elementModel;
			break;

		case TITLE_ROW:
			ITitleRowModel titleRowModel = (ITitleRowModel) elementModel;

			if (titleRowModel.isFocusable() == false) {
				// Can not happen !
				return false;
			}

			titleCellModel = getLastActivedTitleCellModel(viewModel,
					titleRowModel, true);
			if (titleCellModel == null) {
				return false;
			}
			break;

		default:
			return false;
		}

		focusProvider.setFocusElement(viewModel, titleCellModel);

		focusProvider.getFocus();

		return true;
	}

	@Override
	public boolean processBlur(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		IFocusProvider focusProvider = gridWidget.getFocusProvider();
		if (focusProvider == null) {
			return false;
		}

		focusProvider.looseFocus();
		return true;
	}

	@Override
	public boolean processOut(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		IOverProvider overProvider = gridWidget.getOverProvider();

		if (overProvider == null) {
			return true;
		}

		overProvider.setOverElement(null);

		return true;
	}

	@Override
	public boolean processOver(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {
		ITitleCellModel titleCellModel = DefaultGridController
				.getTitleCellModel(elementModel);
		if (titleCellModel == null) {
			return false;
		}

		IOverProvider overProvider = gridWidget.getOverProvider();
		if (overProvider == null) {
			return true;
		}

		overProvider.setOverElement(titleCellModel);

		return true;
	}

	@Override
	public boolean processKeyPress(IGridModelController gridModelController,
			IGridWidget gridWidget, IElementModel elementModel, Event event) {

		if (elementModel.getType() != IElementModel.Type.TITLE_ROW) {
			return false;
		}

		ITitleRowModel titleRowModel = (ITitleRowModel) elementModel;

		int keyCode = event.getKeyCode();

		IFocusProvider focusProvider = gridWidget.getFocusProvider();
		if (focusProvider == null) {
			return true;
		}

		IElementModel focusedElementModel = focusProvider
				.getFocusElementModel();

		ITitleCellModel focusedTitleCellModel = null;
		int focusedRowRenderedIndex = -1;

		if (focusedElementModel != null
				&& focusedElementModel.getType() == IElementModel.Type.TITLE_CELL) {
			focusedTitleCellModel = (ITitleCellModel) focusedElementModel;

			if (focusedTitleCellModel != null) {

				focusedRowRenderedIndex = getRenderedIndex(focusedTitleCellModel);

				if (focusedRowRenderedIndex < 0) {
					focusedTitleCellModel = null;
				}
			}
		}

		switch (keyCode) {
		case KeyCodes.KEY_LEFT:
			if (focusedTitleCellModel == null) {
				selectTitleCellIndex(gridModelController, titleRowModel, 0,
						event);
				cancelEvent(event);
				return true;
			}

			selectTitleCellIndex(gridModelController, titleRowModel,
					focusedRowRenderedIndex - 1, event);
			cancelEvent(event);
			return true;

		case KeyCodes.KEY_RIGHT:
			if (focusedTitleCellModel == null) {
				selectTitleCellIndex(gridModelController, titleRowModel, -1,
						event);
				cancelEvent(event);
				return true;
			}

			int index = focusedRowRenderedIndex + 1;

			if (getTitleCellModelByRenderedIndex(titleRowModel, index) == null) {
				index = 0;
			}

			selectTitleCellIndex(gridModelController, titleRowModel, index,
					event);
			cancelEvent(event);
			return true;

		case KeyCodes.KEY_ENTER:
			performColumnSort(gridModelController, focusedTitleCellModel, event);
			cancelEvent(event);
			return true;

		case KeyCodes.KEY_DOWN:
			showPopup(gridModelController, focusedTitleCellModel, event);
			cancelEvent(event);
			return true;
		}

		return false;
	}

	protected void cancelEvent(Event event) {
		event.stopPropagation();
		event.preventDefault();
	}

	protected void selectTitleCellIndex(
			IGridModelController gridModelController,
			ITitleRowModel titleRowModel, int index, Event event) {

		ITitleCellModel titleCellModel = getTitleCellModelByRenderedIndex(
				titleRowModel, index);

		selectTitleCellModel(gridModelController, titleCellModel, event);
	}

	protected void selectTitleCellModel(
			IGridModelController gridModelController,
			ITitleCellModel titleCellModel, Event event) {
		if (titleCellModel == null) {
			return;
		}

		lastActivedTitleCellModelIndex = titleCellModel.getModelIndex();

		processFocus(gridModelController, titleCellModel.getGridModel()
				.getGridWidget(), titleCellModel, event);
	}

	@Override
	public boolean processSelection(IGridModelController gridModelController,
			final IGridWidget gridWidget, IElementModel elementModel,
			final Event event) {
		ITitleCellModel titleCellModel = DefaultGridController
				.getTitleCellModel(elementModel);
		if (titleCellModel == null) {
			return false;
		}

		IViewModel viewModel = DefaultGridController.getViewModel(gridWidget,
				event);
		viewModel.show(titleCellModel);

		if (isPopupMarkerElement(gridModelController, titleCellModel, event)) {
			showPopup(gridModelController, titleCellModel, event);
			return true;
		}

		processSelection(gridModelController, gridWidget, titleCellModel, event);

		return true;
	}

	protected void showPopup(IGridModelController gridModelController,
			ITitleCellModel titleCellModel, Event event) {
		Window.alert("Show popup");
	}

	protected void processSelection(IGridModelController gridModelController,
			IGridWidget gridWidget, ITitleCellModel titleCellModel, Event event) {

		if (titleCellModel.getColumnModel().getColumn().isSortable() == false) {
			return;
		}

		titleCellModel.updateStateMask(~IStateMasks.SELECTED_STATE_MASK,
				IStateMasks.SELECTED_STATE_MASK);

		currentPushedTitleCell = titleCellModel;
		lastActivedTitleCellModelIndex = titleCellModel.getModelIndex();

		gridModelController
				.setCaptureEventListener(new ICaptureEventListener() {

					@Override
					public boolean onBrowserEvent(
							IGridModelController gridModelController,
							IGridWidget gridWidget, IElementModel elementModel,
							Event event) {

						switch (event.getTypeInt()) {
						case Event.ONMOUSEUP:
							ITitleCellModel titleCellModel = currentPushedTitleCell;

							releasePushedTitleCell(gridWidget);
							gridModelController.releaseCapture(this);

							performColumnSort(gridModelController,
									titleCellModel, event);

							break;

						case Event.ONMOUSEOUT:
						case Event.ONMOUSEOVER:
							releasePushedTitleCell(gridWidget);

							gridModelController.releaseCapture(this);
							return true;

						default:
							break;
						}

						return false;
					}
				});
	}

	private boolean isPopupMarkerElement(
			IGridModelController gridModelController,
			ITitleCellModel titleCellModel, Event event) {

		IGridWidget gridWidget = titleCellModel.getGridModel().getGridWidget();

		IViewModel viewModel = DefaultGridController.getViewModel(gridWidget,
				event);

		IGridRenderContext gridRenderContext = gridWidget
				.getGridRenderContext();

		IViewRenderContext viewRenderContext = gridRenderContext
				.getViewRenderContext(viewModel);

		ITitleCellRenderer titleCellRenderer = gridRenderContext.getTheme()
				.getTitleCellRenderer(titleCellModel);

		Element targetElement = DOM.eventGetTarget(event);

		Element titleCellElement = viewModel.getViewModelElements()
				.getTitleCellElement(titleCellModel);

		boolean clicked = titleCellRenderer.isPopupMarkerClicked(
				viewRenderContext, titleCellModel, titleCellElement,
				targetElement);

		return clicked;
	}

	protected boolean isAppendMode(Event event) {
		return event.getCtrlKey();
	}

	protected boolean isRangeMode(Event event) {
		return event.getShiftKey();
	}

	protected void performColumnSort(IGridModelController gridModelController,
			ITitleCellModel titleCellModel, Event event) {

		IGridWidget gridWidget = titleCellModel.getGridModel().getGridWidget();

		IOrderProvider orderProvider = gridWidget.getColumnsOrderProvider();
		if (orderProvider == null) {
			return;
		}

		int modelIndex = titleCellModel.getModelIndex();

		if (orderProvider.getOrderState(modelIndex) != null) {
			orderProvider.changeOrderDirection(modelIndex);

		} else if (isAppendMode(event)) {
			orderProvider.appendOrder(titleCellModel.getModelIndex(), true);

		} else {
			orderProvider.setOrder(titleCellModel.getModelIndex(), true);
		}

		// Redonne le focus au body !
		gridModelController.giveFocus(gridWidget, titleCellModel.getParent()
				.getParent().getParent(), event);
	}

	private void releasePushedTitleCell(IGridWidget gridWidget) {

		if (currentPushedTitleCell == null) {
			return;
		}

		currentPushedTitleCell.updateStateMask(
				~IStateMasks.SELECTED_STATE_MASK, 0);

		currentPushedTitleCell = null;
	}

	protected ITitleCellModel getLastActivedTitleCellModel(
			IViewModel viewModel, ITitleRowModel titleRowModel,
			boolean computeDefaultOne) {

		if (lastActivedTitleCellModelIndex >= 0) {
			ITitleCellModel titleCellModel = titleRowModel
					.searchTitleCellModel(lastActivedTitleCellModelIndex);
			if (titleCellModel != null) {
				return titleCellModel;
			}
		}

		if (computeDefaultOne == false) {
			return null;
		}

		ITitleCellModel titleCellModel = getTitleCellModelByRenderedIndex(
				titleRowModel, 0);

		return titleCellModel;
	}

	protected ITitleCellModel getTitleCellModelByRenderedIndex(
			ITitleRowModel titleRowModel, int renderedIndex) {

		IViewModel viewModel = titleRowModel.getHeader().getViewModel();

		IGridModel gridModel = viewModel.getGridModel();

		ITitleRowRenderer titleRowRenderer = gridModel.getGridWidget()
				.getTheme().getTitleRowRenderer(titleRowModel);

		Element titleRowElement = viewModel.getViewModelElements()
				.getTitleRowElement(titleRowModel);

		IViewRenderContext viewRenderContext = gridModel.getGridWidget()
				.getGridRenderContext().getViewRenderContext(viewModel);

		return titleRowRenderer.getTitleCellModelByRenderedIndex(
				viewRenderContext, titleRowModel, titleRowElement,
				renderedIndex);
	}

	protected int getRenderedIndex(ITitleCellModel titleCellModel) {
		ITitleRowModel titleRowModel = titleCellModel.getTitleRowModel();

		IViewModel viewModel = titleRowModel.getHeader().getViewModel();

		IGridModel gridModel = viewModel.getGridModel();

		ITitleRowRenderer titleRowRenderer = gridModel.getGridWidget()
				.getTheme().getTitleRowRenderer(titleRowModel);

		Element titleRowElement = viewModel.getViewModelElements()
				.getTitleRowElement(titleRowModel);

		IViewRenderContext viewRenderContext = gridModel.getGridWidget()
				.getGridRenderContext().getViewRenderContext(viewModel);

		return titleRowRenderer.getTitleCellRenderedIndex(viewRenderContext,
				titleRowModel, titleRowElement, titleCellModel);

	}

	protected void setLastActivedTitleCellModel(ITitleCellModel titleCellModel) {
		if (titleCellModel == null) {
			lastActivedTitleCellModelIndex = -1;
			return;
		}
		lastActivedTitleCellModelIndex = titleCellModel.getModelIndex();
	}

}
